package com.tomtop.core.dorequest;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.tomtop.core.dorequest.DoHttpRequest.judge;
import com.tomtop.core.utils.ListUtils;
import com.tomtop.core.utils.StringUtils;

public class AnnotationAnalysis {
    private final static Logger LOGGER = LoggerFactory.getLogger(AnnotationAnalysis.class);

    /**
     * 处理注解参数,如果已缓存，就从缓存返回
     * @param annotation
     * @param classannotation
     * @return
     * @throws SecurityException 
     * @throws NoSuchMethodException 
     */
    /**
     * 需要解析的参数注解
     */
	private final static  List<String> ats=ListUtils.<String>n().a(RequestParam.class.getTypeName(),RequestHeader.class.getTypeName(),RequestBody.class.getName(),CookieValue.class.getTypeName(),  PathVariable.class.getTypeName()).to();
    
    private final static Map<Method,DoHttpRequestData> cachemap=new LinkedHashMap<>();
    public static DoHttpRequestData initMethodParameter(ProceedingJoinPoint point) throws NoSuchMethodException, SecurityException {
    	MethodSignature ms = (MethodSignature) point.getSignature();
    	Method imethod = ms.getMethod();
    	if(cachemap.containsKey(imethod))
    		return cachemap.get(imethod);
    	String parameterTypes = ListUtils.<Type>n().a(imethod.getParameterTypes()).list(t->t.getTypeName()).join(",");
    	Class<?> targetClass = point.getTarget().getClass();
        String methodKey=targetClass.getName()+"."+imethod.getName()+"["+parameterTypes+"]";
        DoHttpRequest classRequest = AnnotationUtils.findAnnotation(targetClass, DoHttpRequest.class) ;
        RequestMapping requestMapping = AnnotationUtils.findAnnotation(targetClass, RequestMapping.class);
        Method method=targetClass.getMethod(imethod.getName(),  imethod.getParameterTypes());
		DoHttpRequest methodRequest = AnnotationUtils.findAnnotation(method, DoHttpRequest.class) ;
        RequestMapping methodRequestMapping = AnnotationUtils.findAnnotation(method, RequestMapping.class);
        String[] paramNames=ms.getParameterNames();
        
    	DoHttpRequestData requestData=new DoHttpRequestData();
    	initRequestData(requestData, classRequest);
    	initRequestData(requestData, requestMapping);
    	initRequestData(requestData, methodRequest);
    	initRequestData(requestData, methodRequestMapping);
    	requestData.setPath(path(requestData.getPath()));
    	requestData.setMethodKey(methodKey);
		requestData.setVariable(initParamData(method,paramNames));
    	requestData.setReturnType(imethod.getGenericReturnType());
    	cachemap.put(imethod, requestData);
    	return requestData;
    }
    
    private static Map<Integer,Map<String,List<Integer>>> initParamData(Method method,String[] paramNames ){
    	Annotation[][] annotations=method.getParameterAnnotations();
    	Map<Integer,Map<String,List<Integer>>> paramData=new LinkedHashMap<>();
    	for (int num = 0; num < annotations.length; num++) {
    		Annotation[] annt = annotations[num];
    		for (Annotation annotation : annt) {
    			int index = ats.indexOf(annotation.annotationType().getTypeName());
    			if(index==-1)
    				continue;
    			Map<String,List<Integer>> map = paramData.get(index);
    			if(map==null)
    				map=new LinkedHashMap<>();
    			String attname = getAnnotationName(annotation,paramNames[num]);
    			List<Integer> list = map.get(attname);
    			if(list==null)
    				list=new LinkedList<>();
    			list.add(num);
    			map.put(attname, list);
    			paramData.put(index, map);
			}
		}
    	return paramData;
    }
    private static String getAnnotationName(Annotation annotation,String defaultvalue) {
		try {
			String name = (String)AnnotationUtils.getValue(annotation, "name");
			String value = (String)AnnotationUtils.getValue(annotation, "value");
//			String defaultValue = (String)AnnotationUtils.getValue(annotation, "defaultValue");
			if(StringUtils.isNotEmpty(name))
				return name;
			if(StringUtils.isNotEmpty(value))
				return value;
		} catch (Exception e) {
			LOGGER.info("数据提起失败",e);
		}
		return defaultvalue;
	}
    
    private static void initRequestData(DoHttpRequestData requestData,DoHttpRequest request) {
    	if(request==null)
    		return;
    	if(request.isfrom()!=judge.auto)
    		requestData.setFrom(request.isfrom()==judge.yes);
    	if(request.iscache()!=judge.auto)
    		requestData.setCache(request.iscache()==judge.yes);
    	if(request.isHttps()!=judge.auto)
    		requestData.setScheme(request.isHttps()==judge.yes?"https":"http");
    	if(request.manuallyprocessed()!=judge.auto)
    		requestData.setManuallyprocessed(request.manuallyprocessed()==judge.yes);
		requestData.setMethod(request.method());
    	if(StringUtils.isNotEmpty(request.path()))
    		requestData.setPath(request.path()); 
    	if(StringUtils.isNotEmpty(request.version()))
    		requestData.setVersion(request.version()); 
    	if(StringUtils.isNotEmpty(request.hostKey()))
    		requestData.setHostKey(request.hostKey());
    	if(request.cacheTimeout()!=-1)
    		requestData.setCachetimeout(request.cacheTimeout());
	}
    
    private static void initRequestData(DoHttpRequestData requestData,RequestMapping request) {
    	if(request==null)
    		return;
    	
	}
    
    /**
     * 格式化请求url
     * @param urlpath
     * @return
     */
   private static String  path(String urlpath){
	   if(StringUtils.isEmpty(urlpath))
		   return "";
	   String[] urlpaths = urlpath.split("\\?");
	   String burlpath = urlpaths[0];
	   int bindex=burlpath.length();
	   burlpath="/"+burlpath;
	   burlpath=burlpath.replaceAll("/{2,}", "/");
	   if(urlpaths.length==1) return burlpath;
	   return burlpath+urlpath.substring(bindex);
    }
}
